#include "Thread.h"

#include <process.h>

#include "Win32Exception.h"

///////////////////////////////////////////////////////////////////////////////
// Lint options
//
//lint -save
//lint -esym(1763, CThread::GetHandle) const member indirectly modifies obj
//
// Member not defined
//lint -esym(1526, CThread::CThread)
//lint -esym(1526, CThread::operator=)
//
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// Namespace: OldDreamTools::Win32
///////////////////////////////////////////////////////////////////////////////

namespace OldDreamTools {
namespace Win32 {

///////////////////////////////////////////////////////////////////////////////
// CThread
///////////////////////////////////////////////////////////////////////////////

CThread::CThread()
   :  m_hThread(INVALID_HANDLE_VALUE)
{

}

CThread::~CThread()
{
   if (m_hThread != INVALID_HANDLE_VALUE)
   {
      ::CloseHandle(m_hThread);
   }

   //lint -e{1540} m_hThread neither freed nor zeroed in destructor
}

HANDLE CThread::GetHandle() const
{
   return m_hThread;
}

void CThread::Start()
{
   if (m_hThread == INVALID_HANDLE_VALUE)
   {
      unsigned int threadID = 0;

      m_hThread = (HANDLE)::_beginthreadex(0, 0, ThreadFunction, (void*)this, 0, &threadID);

      if (m_hThread == INVALID_HANDLE_VALUE)
      {
         throw CWin32Exception(_T("CThread::Start() - _beginthreadex"), GetLastError());
      }
   }
   else
   {
      throw CException(_T("CThread::Start()"), _T("Thread already running - you can only call Start() once!"));
   }
}

void CThread::Wait() const
{
   if (!Wait(INFINITE))
   {
      throw CException(_T("CThread::Wait()"), _T("Unexpected timeout on infinite wait"));
   }
}

bool CThread::Wait(DWORD timeoutMillis) const
{
   // TODO base class? Waitable?
   bool ok;

   DWORD result = ::WaitForSingleObject(m_hThread, timeoutMillis);

   if (result == WAIT_TIMEOUT)
   {
      ok = false;
   }
   else if (result == WAIT_OBJECT_0)
   {
      ok = true;
   }
   else
   {
      throw CWin32Exception(_T("CThread::Wait() - WaitForSingleObject"), ::GetLastError());
   }

   return ok;
}

unsigned int __stdcall CThread::ThreadFunction(void *pV)
{
   int result = 0;

   CThread* pThis = (CThread*)pV;

   if (pThis)
   {
      try
      {
         result = pThis->Run();
      }
      catch(...)
      {
      }
   }

   return result;
}

void CThread::Terminate(
   DWORD exitCode /* = 0 */)
{
   if (!::TerminateThread(m_hThread, exitCode))
   {
      // TODO we could throw an exception here...
   }
}

///////////////////////////////////////////////////////////////////////////////
// Namespace: OldDreamTools::Win32
///////////////////////////////////////////////////////////////////////////////

} // End of namespace Win32
} // End of namespace OldDreamTools

///////////////////////////////////////////////////////////////////////////////
// Lint options
//
//lint -restore
//
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// End of file...
///////////////////////////////////////////////////////////////////////////////

